#ifndef NSERVERCORE_H
#define NSERVERCORE_H


#include <QtCore>
#include <QtNetwork>
#include <QtSql>
#include <QCryptographicHash>
#include <QMessageBox>

#include "ninterfaceimplalgadd.h"
#include "ninterfaceimplalgexecute.h"
#include "ninterfaceimpldatabase.h"
#include "ninterfaceimplusermanager.h"

#define DEFAULT_CONFIG QString::fromLocal8Bit("./main.conf")
#define SOCK_BUFFER_SIZE 65500

struct NIncomeConnect
{
    QTcpSocket *sock;
    unsigned char sockBuf[SOCK_BUFFER_SIZE+1];   //msg buffer for avoid tcp fragmentation
    uint sockBufCnt;                             //msg buffer fill count

    NIncomeConnect()
    {
        sock = NULL;
        sockBufCnt = 0;
        memset(sockBuf, 0, SOCK_BUFFER_SIZE);
    }
};

class NNetProtocol    //работа с сетью
{
private:
    QByteArray reqUrl, msgBody;
    int dataLen;
    QList<QByteArray> headers;

public:
    NNetProtocol()
    {
        dataLen = 0;
    }

    //методы!
    bool checkDataForMessage(QByteArray curStr)
    {
        int ind2 = curStr.indexOf("\r\n\r\n");
        int ind = QString(curStr).toUpper().indexOf("CONTENT-LENGTH: ");
        if (ind < 0)
            ind = QString(curStr).toUpper().indexOf("CONTENT LENGTH: ");    //AJAX POST REQ??
        int indBeginLen = ind + QByteArray("CONTENT-LENGTH: ").length();
        int indEndLen = curStr.indexOf("\r\n", indBeginLen);
        int len = curStr.mid(indBeginLen, indEndLen-indBeginLen).trimmed().toUInt();

        //qDebug("ind2: %d, ind: %d, ingBBB: %d, len: %d", ind2, ind, indBeginLen, len);

        int indReq1 = curStr.indexOf(" ") + 1;
        int indReq2 = curStr.indexOf(" ", indReq1);
        reqUrl = curStr.mid(indReq1, indReq2-indReq1).trimmed();

        headers.clear();
        headers = curStr.left(ind2).split('\n');

        msgBody = curStr.mid(ind2+4);
        dataLen = len;

        return ((ind2 > 0) && ((ind < 0) || ((curStr.length()-(ind2+4)) == len)));
    }

    QByteArray getReqUrl()
    {
        return reqUrl;
    }
    QList<QByteArray> getHeaders()
    {
        return headers;
    }
    QByteArray getMsgBody()
    {
        return msgBody;
    }
    int getDataLength()
    {
        return dataLen;
    }

    ~NNetProtocol() { }
};

class NServerCore : public QObject      //QTcpServer
{
    Q_OBJECT

private:
    ///int tmrCheckKA, tmrGamePeriod;

    QTcpServer *tcpSrvHttp;
    NNetProtocol *netProtocol;

    //settings
    ushort  settsHttpPort;  //settsPort, settsDBPort,
    QString settsCompiler, settsBaseDir;

    //используемые интерфейсы
    IDatabase *db;
    IAlgorithmExecute *algExec;
    IAlgorithmAdd *algAdding;
    IUserManager *userManager;

    QVector<NIncomeConnect> connHttp;

    QMap<int, QByteArray> authDataCache;
    QMap<int, int> authDataGroup;

public:
    NServerCore(QString configPath, QObject* parent = 0);
    ~NServerCore();

    void pause();
    void resume();

    void timerEvent(QTimerEvent* e);

    void httpProcessPacket(int connId, uint len, bool isGetReq, QByteArray requestUrl, QByteArray content, QList<QByteArray> cookies);
    void httpSendAnswer(QTcpSocket *sock, uint respCode, QByteArray contentExt, QByteArray content, QString cookies);
    void httpSendRedirect(QTcpSocket *sock, QString url, QString cookies);

    QByteArray getWWWFile(QByteArray path);     //if no file, returns NULL qbytearray!

    ///bool isDBOpen() { return db.isOpen(); }

public slots:

    void httpIncomingConnection();
    void httpReadClient();
    void httpDiscardClient();
};

#endif
